package org.example.y24.m11;

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Random;

public class MazeSolverPathGUI extends JFrame {
    private static final int MIN_SIZE = 5;
    private static final int MAX_SIZE = 50;
    private static final int CELL_SIZE = 20;
    private static final int EMPTY = 0;
    private static final int OBSTACLE = 1;
    private static final int VISITED = 2;
    private static final int START = 3;
    private static final int END = 4;
    private static final float OBSTACLE_RANDOM = 0.4F;
    private static Integer w;

    private int size;
    private int[][] maze;
    private int startX, startY, endX, endY;
    private boolean solving = false;

    public MazeSolverPathGUI() {
        setTitle("最短路径");
        generateMaze();

        setSize(1100, 1150);
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel panel = new JPanel() {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                w = (1100 - size * CELL_SIZE) / 2;
                for (int i = 0; i < size; i++) {
                    for (int j = 0; j < size; j++) {
                        switch (maze[i][j]) {
                            case EMPTY:
                                g.setColor(Color.BLUE);
                                break;
                            case OBSTACLE:
                                g.setColor(Color.YELLOW);
                                break;
                            case VISITED:
                                g.setColor(Color.BLACK);
                                break;
                            case START:
                                g.setColor(Color.WHITE);
                                break;
                            case END:
                                g.setColor(Color.RED);
                                break;
                        }
                        g.fillRect(j * CELL_SIZE + w, i * CELL_SIZE + w, CELL_SIZE, CELL_SIZE);
                    }
                }
            }
        };

        JButton startButton = new JButton("开始");
        JButton resetButton = new JButton("重置");
        startButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (!solving) {
                    solving = true;
                    solveMaze(panel);
                }
            }
        });
        resetButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                solving = false;
                generateMaze();
            }
        });

        setLayout(new BorderLayout());
        add(panel, BorderLayout.CENTER);
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(startButton);
        buttonPanel.add(resetButton);
        add(buttonPanel, BorderLayout.SOUTH);
    }

    private void generateMaze() {
        Random random = new Random();
        size = random.nextInt(MAX_SIZE - MIN_SIZE + 1) + MIN_SIZE;
        maze = new int[size][size];

        for (int i = 0; i < size; i++) {
            for (int j = 0; j < size; j++) {
                maze[i][j] = random.nextFloat() < OBSTACLE_RANDOM ? OBSTACLE : EMPTY;
            }
        }

        do {
            startX = random.nextInt(size);
            startY = random.nextInt(size);
        } while (maze[startX][startY] == OBSTACLE);

        do {
            endX = random.nextInt(size);
            endY = random.nextInt(size);
        } while (maze[endX][endY] == OBSTACLE || (startX == endX && startY == endY));

        maze[startX][startY] = START;
        maze[endX][endY] = END;

        repaint();
    }

    private void solveMaze(JPanel panel) {
        if (maze == null) {
            JOptionPane.showMessageDialog(this, "迷宫尚未生成。");
            solving = false;
            return;
        }

        Queue<Node> queue = new LinkedList<>();
        queue.offer(new Node(startX, startY, 0, null));
        maze[startX][startY] = VISITED;

        int shortestPathLength = Integer.MAX_VALUE;
        Node endNode = null;

        while (!queue.isEmpty()) {
            Node current = queue.poll();
            int x = current.x, y = current.y, pathLength = current.distance;

            if (x == endX && y == endY) {
                endNode = current;
                break;
            }

            int[][] directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
            for (int[] dir : directions) {
                int newX = x + dir[0], newY = y + dir[1];
                if (newX >= 0 && newX < size && newY >= 0 && newY < size && (maze[newX][newY] == EMPTY || maze[newX][newY] == END) && pathLength + 1 <= shortestPathLength) {
                    queue.offer(new Node(newX, newY, pathLength + 1, current));
                    maze[newX][newY] = VISITED;
                    draw(panel, newX, newY, Color.BLACK);
                }
            }

            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }

        if (endNode != null) {
            markShortestPath(endNode, panel);
            JOptionPane.showMessageDialog(this, "最短路径长度: " + endNode.distance);
        } else {
            JOptionPane.showMessageDialog(this, "没有找到路径。");
        }

        solving = false;
    }

    private void markShortestPath(Node endNode, JPanel panel) {
        Node current = endNode;
        while (current != null) {
            int x = current.x, y = current.y;
            if (maze[x][y] != START) {
                maze[x][y] = VISITED;
                draw(panel, x, y, Color.GREEN);
            }
            current = current.parent;
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            MazeSolverPathGUI frame = new MazeSolverPathGUI();
            frame.setVisible(true);
        });
    }

    private void draw(JPanel panel, int x, int y, Color color) {
        Graphics g = panel.getGraphics();
        if (g != null) {
            g.setColor(color);
            g.fillRect(y * CELL_SIZE + w, x * CELL_SIZE + w, CELL_SIZE, CELL_SIZE);
        }
    }

    private static class Node {
        int x, y, distance;
        Node parent;

        Node(int x, int y, int distance) {
            this(x, y, distance, null);
        }

        Node(int x, int y, int distance, Node parent) {
            this.x = x;
            this.y = y;
            this.distance = distance;
            this.parent = parent;
        }
    }
}